<template>
  <div class="app">
    <!-- 游戏结束弹框：全局显示，确保不被遮挡 -->
    <div v-if="gameOver" class="modal-overlay">
      <div class="modal">
        <h2>游戏结束</h2>
        <p>最终分数: {{ score }}</p>
        <button @click="restartGame">重新开始</button>
      </div>
    </div>
    <h1>贪吃蛇游戏</h1>
    <div class="game-section">
      <div class="game-container">
        <div class="game-info">
          <div class="score">分数: {{ score }}</div>
          <div class="lives">生命: {{ lives }}</div>
        </div>
        <canvas ref="gameCanvas" class="game-canvas"></canvas>
      </div>
      <div class="game-sidebar">
        <div class="food-info">
          <h3>食物说明</h3>
          <div v-for="(type, key) in foodTypes" :key="key" class="food-type">
            <span class="emoji">{{ type.emoji }}</span>
            <span class="description">{{ getFoodDescription(key) }}</span>
          </div>
        </div>
        <div class="leaderboard">
          <h2>排行榜</h2>
          <div class="scores">
            <div v-for="(score, index) in highScores" :key="index" class="score-item">
              <span class="rank">#{{ index + 1 }}</span>
              <span class="score">{{ score.score }}</span>
              <span class="date">{{ score.date }}</span>
            </div>
            <div v-if="highScores.length === 0" class="no-scores">
              暂无记录
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
export default {
  name: 'App',
  data() {
    return {
      canvas: null,
      ctx: null,
      snake: [],
      food: {},
      direction: { x: 1, y: 0 },
      score: 0,
      lives: 3,
      gameOver: false,
      gameLoop: null,
      gridSize: 20,
      speed: 10,
      speedEffectTime: 0,
      
      highScores: [],
      //
      foodTypes: {
        normal: { 
          color: '#00ff00', 
          score: 10, 
          duration: 0,
          emoji: '🍎',
          probability: 0.6
        },
        speedUp: { 
          color: '#ff0000', 
          score: 5, 
          duration: 2,
          emoji: '🚀',
          probability: 0.15
        },
        speedDown: { 
          color: '#0000ff', 
          score: 5, 
          duration: 2,
          emoji: '🛑',
          probability: 0.15
        },
        life: { 
          color: '#ffc0cb', 
          score: 0, 
          duration: 0,
          emoji: '❤️',
          probability: 0.1
        }
      }
    }
  },
  mounted() {
    this.initGame()
    document.addEventListener('keydown', this.handleKeyPress)
    this.loadHighScores()
  },
  beforeUnmount() {
    document.removeEventListener('keydown', this.handleKeyPress)
    if (this.gameLoop) {
      cancelAnimationFrame(this.gameLoop)
    }
  },
  methods: {
    
    getFoodDescription(type) {
      const food = this.foodTypes[type]
      switch(type) {
        case 'normal':
          return `普通食物：+${food.score}分`
        case 'speedUp':
          return `加速食物：蛇速提升${food.duration}秒`
        case 'speedDown':
          return `减速食物：蛇速降低${food.duration}秒`
        case 'life':
          return `生命食物：+1生命`
        default:
          return ''
      }
    },
    initGame() {
      this.canvas = this.$refs.gameCanvas
      this.ctx = this.canvas.getContext('2d')
      this.canvas.width = 800
      this.canvas.height = 600
      
      // 初始化蛇
      this.snake = [
        { x: 10, y: 10 }
      ]
      this.direction = { x: 1, y: 0 }
      this.score = 0
      this.lives = 3
      this.gameOver = false
      this.speed = 10
      
      // 初始化食物
      this.generateFood()
      
      // 开始游戏循环
      if (this.gameLoop) {
        cancelAnimationFrame(this.gameLoop)
      }
      this.gameLoop = requestAnimationFrame(this.update)
    },
    
    generateFood() {
      const foodTypes = Object.keys(this.foodTypes)
      const weights = foodTypes.map(type => this.foodTypes[type].probability)
      const type = this.weightedRandom(foodTypes, weights)
      
      // 确保食物不会生成在蛇身上
      let newPosition
      do {
        newPosition = {
          x: Math.floor(Math.random() * (this.canvas.width / this.gridSize)),
          y: Math.floor(Math.random() * (this.canvas.height / this.gridSize))
        }
      } while (this.snake.some(segment => segment.x === newPosition.x && segment.y === newPosition.y))
      
      this.food = {
        ...newPosition,
        type: type
      }
    },
    
    weightedRandom(items, weights) {
      const total = weights.reduce((a, b) => a + b, 0)
      let random = Math.random() * total
      
      for (let i = 0; i < items.length; i++) {
        if (random < weights[i]) return items[i]
        random -= weights[i]
      }
      
      return items[0]
    },
    
    update() {
      if (this.gameOver) return
      
      // 检查速度效果是否过期
      if (this.speedEffectTime && Date.now() > this.speedEffectTime) {
        this.speed = 10
        this.speedEffectTime = 0
      }
      
      // 移动蛇
      const head = { ...this.snake[0] }
      head.x += this.direction.x
      head.y += this.direction.y
      
      // 检查碰撞
      if (this.checkCollision(head)) {
        this.lives--
        if (this.lives <= 0) {
          this.gameOver = true
          this.handleGameOver()
          return
        }
        this.resetSnake()
        return
      }
      
      this.snake.unshift(head)
      
      // 检查是否吃到食物
      if (head.x === this.food.x && head.y === this.food.y) {
        this.handleFoodCollision()
      } else {
        this.snake.pop()
      }
      
      // 绘制游戏
      this.draw()
      
      // 使用setTimeout控制游戏速度
      setTimeout(() => {
        this.gameLoop = requestAnimationFrame(this.update)
      }, 1000 / this.speed)
    },
    
    checkCollision(head) {
      // 检查墙壁碰撞
      if (head.x < 0 || head.x >= this.canvas.width / this.gridSize ||
          head.y < 0 || head.y >= this.canvas.height / this.gridSize) {
        return true
      }
      
      // 检查自身碰撞
      return this.snake.some(segment => segment.x === head.x && segment.y === head.y)
    },
    
    handleFoodCollision() {
      const foodType = this.food.type
      const foodData = this.foodTypes[foodType]
      
      this.score += foodData.score
      
      if (foodType === 'life') {
        this.lives++
        // 显示获得生命的提示
        this.showMessage('获得一条生命！')
      } else if (foodType === 'speedUp') {
        this.speedEffectTime = Date.now() + foodData.duration * 1000
        this.speed = 20
        // 显示加速提示
        this.showMessage('速度提升！')
      } else if (foodType === 'speedDown') {
        this.speedEffectTime = Date.now() + foodData.duration * 1000
        this.speed = 5
        // 显示减速提示
        this.showMessage('速度降低！')
      }
      
      this.generateFood()
    },
    
    resetSnake() {
      this.snake = [{ x: 10, y: 10 }]
      this.direction = { x: 1, y: 0 }
    },
    
    draw() {
      // 清空画布
      this.ctx.fillStyle = '#000000'
      this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height)
      
      // 绘制蛇
      this.ctx.fillStyle = '#00ff00'
      this.snake.forEach((segment, index) => {
        // 蛇头用不同颜色
        if (index === 0) {
          this.ctx.fillStyle = '#00cc00'
        } else {
          this.ctx.fillStyle = '#00ff00'
        }
        this.ctx.fillRect(
          segment.x * this.gridSize,
          segment.y * this.gridSize,
          this.gridSize,
          this.gridSize
        )
      })
      
      // 绘制食物
      const foodData = this.foodTypes[this.food.type]
      this.ctx.fillStyle = foodData.color
      this.ctx.fillRect(
        this.food.x * this.gridSize,
        this.food.y * this.gridSize,
        this.gridSize,
        this.gridSize
      )

      // 在食物上绘制emoji
      this.ctx.font = `${this.gridSize}px Arial`
      this.ctx.textAlign = 'center'
      this.ctx.textBaseline = 'middle'
      this.ctx.fillText(
        foodData.emoji,
        (this.food.x * this.gridSize) + (this.gridSize / 2),
        (this.food.y * this.gridSize) + (this.gridSize / 2)
      )
    },
    
    handleKeyPress(event) {
      // 防止方向键滚动页面
      if(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'w', 'a', 's', 'd'].includes(event.key)) {
        event.preventDefault()
      }

      // 获取当前方向
      const currentDirection = { ...this.direction }

      switch (event.key) {
        case 'ArrowUp':
        case 'w':
        case 'W':
          if (currentDirection.y !== 1) {
            this.direction = { x: 0, y: -1 }
          }
          break
        case 'ArrowDown':
        case 's':
        case 'S':
          if (currentDirection.y !== -1) {
            this.direction = { x: 0, y: 1 }
          }
          break
        case 'ArrowLeft':
        case 'a':
        case 'A':
          if (currentDirection.x !== 1) {
            this.direction = { x: -1, y: 0 }
          }
          break
        case 'ArrowRight':
        case 'd':
        case 'D':
          if (currentDirection.x !== -1) {
            this.direction = { x: 1, y: 0 }
          }
          break
      }
    },
    
    restartGame() {
      this.score = 0
      this.lives = 3
      this.gameOver = false
      this.resetSnake()
      this.generateFood()
      this.gameLoop = requestAnimationFrame(this.update)
    },
    
    loadHighScores() {
      const scores = localStorage.getItem('snakeHighScores')
      if (scores) {
        this.highScores = JSON.parse(scores)
      }
    },
    
    saveHighScores() {
      localStorage.setItem('snakeHighScores', JSON.stringify(this.highScores))
    },
    
    handleGameOver() {
      // 游戏结束时，设置 gameOver 为 true，触发弹框显示
      this.gameOver = true;
      const newScore = {
        score: this.score,
        date: new Date().toLocaleString()
      }
      this.highScores.push(newScore)
      this.highScores.sort((a, b) => b.score - a.score)
      this.highScores = this.highScores.slice(0, 10)
      this.saveHighScores()
    },

    showMessage(message) {
      const messageEl = document.createElement('div')
      messageEl.textContent = message
      messageEl.style.position = 'absolute'
      messageEl.style.top = '50%'
      messageEl.style.left = '50%'
      messageEl.style.transform = 'translate(-50%, -50%)'
      messageEl.style.color = 'white'
      messageEl.style.fontSize = '24px'
      messageEl.style.backgroundColor = 'rgba(0, 0, 0, 0.7)'
      messageEl.style.padding = '10px 20px'
      messageEl.style.borderRadius = '5px'
      messageEl.style.zIndex = '1000'
      
      document.body.appendChild(messageEl)
      
      setTimeout(() => {
        messageEl.remove()
      }, 1000)
    }
  }
}
</script>

<style>
.app {
  max-width: 1200px;
  margin: 0 auto;
  padding: 20px;
  text-align: center;
}

h1 {
  color: #333;
  margin-bottom: 30px;
}

.game-section {
  display: flex;
  flex-direction: row;
  justify-content: center;
  gap: 32px;
}

.game-container {
  position: relative;
  width: 800px;
  height: 600px;
}

.game-canvas {
  border: 2px solid #333;
  background-color: #000;
}

.game-info {
  position: absolute;
  top: 10px;
  left: 10px;
  color: white;
  font-size: 20px;
  z-index: 1;
}

.game-sidebar {
  width: 340px;
  min-width: 300px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  height: 600px;
  gap: 32px;
  box-sizing: border-box;
}

.food-info {
  background-color: #f5f5f5;
  padding: 24px 20px 24px 20px;
  border-radius: 12px;
  text-align: left;
  margin-bottom: 0;
}

.food-info h3 {
  margin-top: 0;
  margin-bottom: 20px;
  color: #333;
  font-size: 22px;
}

.food-type {
  display: flex;
  align-items: center;
  margin: 18px 0;
  padding: 8px 6px;
  background-color: white;
  border-radius: 7px;
  box-shadow: 0 1px 3px rgba(0,0,0,0.04);
}

.emoji {
  margin-right: 14px;
  font-size: 26px;
}

.description {
  font-size: 17px;
  color: #333;
}

.game-over {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background-color: rgba(0, 0, 0, 0.8);
  color: white;
  padding: 20px;
  text-align: center;
  border-radius: 10px;
}

.leaderboard {
  background-color: #f5f5f5;
  padding: 20px;
  border-radius: 12px;
  margin: 0;
  max-height: 260px;
  overflow-y: auto;
  box-sizing: border-box;
}

.leaderboard h2 {
  margin-top: 0;
  margin-bottom: 18px;
  font-size: 22px;
}

.scores {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.score-item {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px;
  background-color: white;
  border-radius: 5px;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.07);
}

.rank {
  font-weight: bold;
  color: #4CAF50;
}

.score {
  font-size: 18px;
  font-weight: bold;
}

.date {
  color: #666;
  font-size: 14px;
}

.no-scores {
  text-align: center;
  color: #666;
  padding: 20px;
}

button {
  margin-top: 10px;
  padding: 10px 20px;
  font-size: 16px;
  cursor: pointer;
  background-color: #4CAF50;
  color: white;
  border: none;
  border-radius: 5px;
}

button:hover {
  background-color: #45a049;
}

@media (min-width: 1024px) {
  .game-section {
    flex-direction: row;
    justify-content: center;
    align-items: flex-start;
  }
  .game-sidebar {
    height: 600px;
  }
}

.modal-overlay {
  position: fixed;
  top: 0; left: 0; right: 0; bottom: 0;
  background: rgba(0,0,0,0.5);
  z-index: 2000;
  display: flex;
  align-items: center;
  justify-content: center;
}

.modal {
  background: #fff;
  border-radius: 12px;
  padding: 40px 32px 32px 32px;
  box-shadow: 0 8px 32px rgba(0,0,0,0.18);
  text-align: center;
  min-width: 320px;
}

.modal h2 {
  margin-top: 0;
  color: #e53935;
}

.modal button {
  margin-top: 24px;
  padding: 12px 32px;
  font-size: 18px;
  background: #4CAF50;
  color: #fff;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  transition: background 0.2s;
}

.modal button:hover {
  background: #388e3c;
}
</style> 